<?php
/**
 * http://code.google.com/p/php-iterator-utils/
 * @license http://www.apache.org/licenses/LICENSE-2.0.html
 * @author Seva Lapsha (seva.lapsha@gmail.com)
 */
namespace lapsha\iterators\generator {
	include_once __DIR__.'/../common.php';
	use \lapsha\common;
	include_once __DIR__.'/common.php';
	use \lapsha\iterators\common\Wrapper;

	class ForGenerator implements Iterator {

		protected $body;
		protected $yielded;
		protected $current;
		protected $key;
		protected $init;
		protected $cond;
		protected $step;

		function __construct($init, $cond, $step, $body) {
			common\checkCallable($init);
			common\checkCallable($cond);
			common\checkCallable($step);
			common\checkCallable($body);
			$this->init = $init;
			$this->cond = $cond;
			$this->step = $step;
			$this->body = $body;
		}
		protected function yield($value, $key = null) {
			$this->yielded = true;
			$this->current = $value;
			if ($key === null)
				++$this->key;
			else
				$this->key = $key;
		}
		function valid() {
			return call_user_func($this->cond, $this);
		}
		function rewind() {
			$result = call_user_func($this->init, $this);
			if (!$this->valid())
				return next();
			return $this->loop();
		}
		function current() {
			return $this->current;
		}
		function next() {
			$this->yielded = false;
			while(!$this->yielded && $this->valid()) {
				$result = call_user_func($this->body, $this);
				if (!$this->valid())
					return $result;
				call_user_func($this->step, $this);
			}
		}
		function key() {
			return $this->key;
		}
	}
	class ForEachGenerator extends ForGenerator {
		function __construct(\Iterator $i, $body) {
			parent::__construct(
				function() use(&$i) {return $i->rewind();},
				function() use(&$i) {return $i->valid();},
				function() use(&$i) {return $i->next();},
				$body
			);
		}
	}
	class WhileGenerator extends ForGenerator {
		function __construct($cond, $body) {
			parent::__construct(
				function() {},
				$cond,
				function() {},
				$body
			);
		}
	}
	class DoGenerator extends ForGenerator {
		function __construct($body, $cond) {
			parent::__construct(
				$body,
				$cond,
				function() {},
				$body
			);
		}
	}


}